package com.polaris.live.im.sfs.core

import android.app.Activity
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.Utils
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.polaris.live.CustomUncaughtExceptionHandler
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.resp.AppIMConfigDto
import com.polaris.live.common.resp.AppIMConfigVo
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.resettableLazy
import com.polaris.live.common.util.resettableManager
import com.polaris.live.dialog.GlobalDialogManager
import com.polaris.live.im.sfs.COMMAND_ERROR
import com.polaris.live.im.sfs.COMMAND_SUCCESS
import com.polaris.live.im.sfs.SmartFoxConfig
import com.polaris.live.im.sfs.bean.event.ImConnectedEvent
import com.polaris.live.im.sfs.bean.event.ImDisconnectedEvent
import com.polaris.live.im.sfs.core.bean.MessageRequest
import com.polaris.live.im.sfs.interfaces.OnAppStatusListener
import com.polaris.live.im.sfs.interfaces.OnImConnectListener
import com.polaris.live.im.sfs.interfaces.OnImMessageListener
import com.polaris.live.im.sfs.interfaces.OnNetworkListener
import com.polaris.live.im.sfs.processor.impl.system.ExcludeMessageProcessor
import com.polaris.live.im.utils.SmartFoxUtils
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.manager.MNotificationManager
import com.polaris.live.utils.UserUtils
import com.smartfoxserver.v2.entities.data.SFSObject
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import sfs2x.client.SmartFox
import sfs2x.client.entities.Room
import sfs2x.client.entities.User
import kotlin.time.Duration.Companion.milliseconds

/**
 * sfs服务管理器
 *
 * 所有im服务的维护
 *
 * @author Created by lucas on 2023/10/18 19:17
 */
object SmartFoxManager : OnImConnectListener,
    OnImMessageListener,
    OnAppStatusListener,
    OnNetworkListener {

    val TAG = "SmartFoxManager"

    //---------- 调度开始
    /**
     * 往下通知的调度，会在主线程
     */
    val noticeDispatcher = Dispatchers.Main

    /**
     * 发送消息的调度
     */
    val sendMessageDispatcher = Dispatchers.Default

    private val handler = CoroutineExceptionHandler { _, e ->
        LogExt.logE(CustomUncaughtExceptionHandler.TAG, "SmartFoxManager", e)

        FirebaseCrashlytics.getInstance().recordException(e)
    }

    private val resettableManager = resettableManager()
    val messageScope by resettableLazy(resettableManager) {
        CoroutineScope(sendMessageDispatcher + SupervisorJob() + handler)
    }

    //---------- 具体逻辑开始

    private val chatConnector: SmartFoxConnector by lazy {
        SmartFoxConnector(SmartFoxConnector.CLIENT_CHAT, this, this)
    }
    private val liveConnector: SmartFoxConnector by lazy {
        SmartFoxConnector(SmartFoxConnector.CLIENT_LIVE, this, this)
    }
    private val pusherConnector: SmartFoxConnector by lazy {
        SmartFoxConnector(SmartFoxConnector.CLIENT_PUSHER, this, this)
    }

    //im的配置
    private var imConfig: AppIMConfigVo? = null

    //是否在前台
    @Volatile
    private var isForeground = true

    //是否允许连接
    @Volatile
    private var isConnected = false

    private var delayDisconnectJob: Job? = null

    init {
        //监听前后台状态
        AppUtils.registerAppStatusChangedListener(object : Utils.OnAppStatusChangedListener {
            override fun onForeground(activity: Activity?) {
                onAppStatus(true)
            }

            override fun onBackground(activity: Activity?) {
                onAppStatus(false)
            }
        })

        //监听网络状态
        NetworkUtils.registerNetworkStatusChangedListener(object : NetworkUtils.OnNetworkStatusChangedListener {
            override fun onConnected(networkType: NetworkUtils.NetworkType?) {
                onNetwork(true)
            }

            override fun onDisconnected() {
                onNetwork(false)
            }
        })

        //清理过期的冗余数据
        ExcludeMessageProcessor.clearRedundancy()

        //当被回收后，重建恢复
        imConfig = AppConfigManager.getConfigPre()?.imConfig
        if (UserManager.isLogin() && imConfig != null) {
            restore()
        }
    }

    /**
     * 设置服务配置
     */
    fun setConfig(config: AppIMConfigVo) {
        val isReconnect: Boolean = imConfig != config
        imConfig = config
        if (UserManager.isLogin() && isReconnect) {
            internalReconnect()
        }
    }

    /**
     * 重置连接，退出登录时
     */
    fun reset() {
        val scope = messageScope
        resettableManager.reset()
        scope.cancel()

        disconnect()
        imConfig = null
    }

    private fun restore() {
        connect()
    }

    /**
     * 强制重连
     */
    fun reconnect() {
        internalReconnect()
    }

    /**
     * 连接服务
     */
    fun connect() {
        synchronized(this) {
            if (isConnected) {
                return
            }
            isConnected = true
            internalConnect()
        }
    }

    /**
     * 断开服务
     */
    fun disconnect() {
        if (!isConnected) {
            return
        }
        isConnected = false
        internalDisconnect()
    }

    /**
     * 所有服务是否连接
     */
    fun isConnected(): Boolean {
        return chatConnector.isConnected() && liveConnector.isConnected() && pusherConnector.isConnected()
    }

    /**
     * 所有服务是否断开连接
     */
    fun isDisconnected(): Boolean {
        return !chatConnector.isConnected() && !liveConnector.isConnected() && !pusherConnector.isConnected()
    }

    /**
     * 消息服务是否连接
     */
    fun isChatConnected(): Boolean {
        return chatConnector.isConnected()
    }

    /**
     * 直播服务是否连接
     */
    fun isLiveConnected(): Boolean {
        return liveConnector.isConnected()
    }

    /**
     * 推送服务是否连接
     */
    fun isPusherConnected(): Boolean {
        return pusherConnector.isConnected()
    }

    private fun internalReconnect() {
        internalDisconnect()
        internalConnect()
    }

    private fun internalConnect() {
        delayDisconnectJob?.cancel()

        val imConfig = imConfig ?: return
        if (!isForeground) {
            return
        }
        if (!isConnected) {
            return
        }
        if (!chatConnector.isConnected()) {
            chatConnector.connect(imConfig.chat.toConfig())
        }
        if (!liveConnector.isConnected()) {
            liveConnector.connect(imConfig.live.toConfig())
        }
        if (!pusherConnector.isConnected()) {
            pusherConnector.connect(imConfig.pusher.toConfig())
        }

        LogExt.logI(TAG, "Connect success")
    }

    //延迟断开连接
    private fun internalDelayDisconnect() {
        if (delayDisconnectJob != null) {
            return
        }
        delayDisconnectJob = CoroutineScope(SmartFoxConnector.connectDispatcher).launch {
            try {
                delay(1000.milliseconds)

                internalDisconnect()

                LogExt.logI(TAG, "Disconnect delay")
            } finally {
                if (delayDisconnectJob == coroutineContext[Job]) {
                    delayDisconnectJob = null
                }
            }
        }
    }

    private fun internalDisconnect() {
        chatConnector.disconnect()
        liveConnector.disconnect()
        pusherConnector.disconnect()
    }

    /**
     * 获取原始直播clent
     */
    fun getLiveClient(): SmartFox? {
        return liveConnector.getClient()
    }

    /**
     * 获取当前直播间加入的房间
     */
    fun getLiveRoom(): Room? {
        return liveConnector.getClient()?.lastJoinedRoom
    }

    /**
     * 获取直播自己的信息
     */
    fun getLiveMyself(): User? {
        return liveConnector.getClient()?.mySelf
    }

    override fun onAppStatus(isForeground: Boolean) {
        SmartFoxManager.isForeground = isForeground
        if (isForeground) {
            internalConnect()
            MNotificationManager.backForeground()
        } else {
            //只有正常状态才关闭连接
            if (LiveStateManager.isNone() && !LiveStateManager.isSpectating()) {
                internalDelayDisconnect()
            }
        }
    }

    override fun onNetwork(isConnected: Boolean) {
        if (isConnected) {
            internalConnect()
        } else {
            internalDisconnect()
        }
    }

    override fun onConnectedReal(type: Int) {
        LogExt.logI(TAG, "%s connect success real", SmartFoxConnector.getName(type))

        when (type) {
            SmartFoxConnector.CLIENT_CHAT -> {
                SmartFoxQueueManager.onChatConnected()
            }
            SmartFoxConnector.CLIENT_LIVE -> {
                SmartFoxQueueManager.onLiveConnected()
            }
            SmartFoxConnector.CLIENT_PUSHER -> {
                SmartFoxQueueManager.onPusherConnected()
            }
        }

        EventBus.getDefault().post(ImConnectedEvent(type))
    }

    override fun onDisconnectedReal(type: Int) {
        LogExt.logI(TAG, "%s disconnect success real", SmartFoxConnector.getName(type))

        when (type) {
            SmartFoxConnector.CLIENT_CHAT -> {
                SmartFoxQueueManager.onChatDisconnected()
            }
            SmartFoxConnector.CLIENT_LIVE -> {
                SmartFoxQueueManager.onLiveDisconnected()
            }
            SmartFoxConnector.CLIENT_PUSHER -> {
                SmartFoxQueueManager.onPusherDisconnected()
            }
        }

        EventBus.getDefault().post(ImDisconnectedEvent(type))
    }

    override fun onConnected(type: Int) {
        LogExt.logI(TAG) {
            val config = when (type) {
                SmartFoxConnector.CLIENT_CHAT -> imConfig?.chat?.toConfig()
                SmartFoxConnector.CLIENT_LIVE -> imConfig?.live?.toConfig()
                SmartFoxConnector.CLIENT_PUSHER -> imConfig?.pusher?.toConfig()
                else -> null
            }?.toString() ?: ""

            "${SmartFoxConnector.getName(type)} connect success address $config"
        }

        if (isConnected()) {
            SmartFoxQueueManager.onConnected()

            EventBus.getDefault().post(ImConnectedEvent(null))
        }
    }

    override fun onDisconnected(type: Int) {
        LogExt.logI(TAG, "%s disconnected success ", SmartFoxConnector.getName(type))

        if (isDisconnected()) {
            SmartFoxQueueManager.onDisconnected()

            EventBus.getDefault().post(ImDisconnectedEvent(null))
        }
    }

    override fun onDisconnectedFailure(type: Int) {
        EventBus.getDefault().post(ImDisconnectedEvent(null))
    }

    override fun onEnterRoom(type: Int, roomId: String) {
        when (type) {
            SmartFoxConnector.CLIENT_CHAT -> {
                SmartFoxQueueManager.onChatEnterRoom(roomId)
            }
            SmartFoxConnector.CLIENT_LIVE -> {
                SmartFoxQueueManager.onLiveEnterRoom(roomId)
            }
            SmartFoxConnector.CLIENT_PUSHER -> {
                SmartFoxQueueManager.onPusherEnterRoom(roomId)
            }
        }
    }

    override fun onKick(type: Int, connectLost: Boolean, msg: String?) {
        CoroutineScope(CoroutineScopeManager.mainDispatcher).launch {
            if (UserUtils.logout() && msg != null) {
                delay(1000)

                GlobalDialogManager.showWarningDialog(msg)
            }
        }
    }

    override suspend fun onMessage(command: String, arguments: Map<String, Any>) {
        when (command) {
            COMMAND_SUCCESS,
            COMMAND_ERROR ->//如果是在后台并且当前没有工作队列
                if (!isForeground && !SmartFoxQueueManager.isWorking()) {
                    onAppStatus(false)
                }
        }

        SmartFoxQueueManager.onMessage(command, arguments)
    }

    /**
     * 发送消息
     */
    fun sendMessage(type: Int, message: MessageRequest) {
        when (type) {
            SmartFoxConnector.CLIENT_CHAT -> {
                chatConnector.sendRequest(message)
            }
            SmartFoxConnector.CLIENT_LIVE -> {
                liveConnector.sendRequest(message)
            }
            SmartFoxConnector.CLIENT_PUSHER -> {
                pusherConnector.sendRequest(message)
            }
        }

        LogExt.logJson(TAG, {
            "${SmartFoxConnector.getName(type)} send message"
        }, {
            val map = mapOf(
                "msgId" to message.msgId,
                "command" to message.command,
                "params" to SmartFoxUtils.flatten(message.params as SFSObject)
            )

            arrayOf(JsonUtils.toJson(map))
        })
    }
}

fun AppIMConfigDto.toConfig(): SmartFoxConfig {
    val user = UserManager.getUser()
    return SmartFoxConfig(
        host,
        port,
        serverName,
        user.userId.toString(),
        user.token ?: ""
    )
}